perm filename INGGP.MAC[IP,SYS]1 blob
sn#680207 filedate 1982-10-14 generic text, type T, neo UTF8
;CWL:<403-INET>INGGP.MAC.40301 29-Jan-82 15:12:05, Edit by CLYNN
; Have GGPINI enter section 1 for MDDT calls
; Updated for IP release 3
; Add global routine FNDPGW to find a prime gateway
; Moved parameters & variables to STG, increased gateway block size
;[BBNF]<402-INET>INGGP.MAC.116 21-Oct-81 17:43;00, Edit by CLYNN
; Fix GGP Echo packet freeing problem
;[BBNF]<402-INET>INGGP.MAC.115, 3-Aug-81 11:00:00, Ed: CLYNN
; Fix: Wrong register at .GGPEC+5; Process all gateways in .GGPER
;[BBNF]<402-INET>INGGP.MAC.114, 13-Jul-81 10:55:00, Ed: CLYNN
; Fix: Save T2 from FINDGW & correct GW%DUM testin .GGPDU
;[BBND]<402-INET>INGGP.MAC.112, 10-Feb-81 09:46:40, Ed: CLYNN
;Increase ping time from 17 to 37 seconds
; GGPPT0==↑D<17*1000> GGPPT0==↑D<37*1000>
;Missing out-of-core error return checks:
; GGPINI+6 CALL GETBLK CALL GETBLK
; JUMPE T1,GGPIN9
;
; GGPI4A+1 CALL GETBLK CALL GETBLK
; JUMPE T1,GGPIN9
;[BBND]SNARK:<402-INET>INGGP.MAC.111, 27-Jan-81 15:44:15, Ed: TAPPAN
;Only a single packet is processed per call, not all received
; GGPDSP+2 MOVE T1,GGPIPQ GGPDS1: MOVE T1,GGPIPQ
;
; GGPDS9: CALL RETPKT CALL RETPKT
; JRST GGPDS1
SEARCH INPAR,PROLOG
TTITLE INGGP
SUBTTL Internet Gateway-Gateway Protocol, Wm. W. Plummer, May79
SWAPCD
COMMENT !
These routines are concerned with keeping this host gateway
in contact with other gateways. Only enough of the GGP is
implemented so that we can operate with out burdening our CPU.
3-6 ...... Definitions
* GGPINI ... 7 ...... Initialize G-G Protocol
LODFIL ... 9 ...... Load the gateway file
* PRCLIN ... 10 ...... Process lines from the gateway file
LOADGW ... 13 ...... Load one gateway description and add to table
GETC ... 17 ...... Get a character from a file
SNDGWD ... 18 ...... Send our gateway file date to all
SNDGFT ... 19 ...... Send gateway file date and source to a gateway
SETROU ... 21 ...... Set routing tables from GW status tables
RSTDSP ... 22 ...... Reset gateway dispatches which are not now set
* GGPPRC ... 23 ...... Top level GGP Processing routine
* GGPCHK ... 23 ...... GGP next run time check routine
PINGER ... 24 ...... Ping gateways to see if they are alive
SNDPNG ... 26 ...... Send a ping message to a gateway
GWDOWN ... 28 ...... Just detected gsteway down
GGPDSP ... 29 ...... Dispatch on GGP message type
31 ...... Gateway message type dispatch tables
.GGPEC ... 32 ...... ECHO message
.GGPER ... 32 ...... ECHO-REPLY message
..GPER ... 32 ...... Work routine for FNDAGW
.GGPRD ... 33 ...... REDIRECT message
.GGPDU ... 34 ...... DESTINATION-UNREACHABLE message
..GPDU ... 34 ...... Work routine for FNDGAW
.GGPRU ... 35 ...... ROUTING-UPDATE message (%FULL only)
.GGPHD ... 36 ...... HOST-DISTANCE message (%FULL only)
.GGPFD ... 37 ...... FILE-DATE message
..GPFD ... 38 ...... Routine to print out new file message
FINDGW ... 39 ...... Set GW to point to gateway block with address in T1
FNDAGW ... 40 ...... For all matching gateway blocks, call a subroutine
* FNDPGW ... 41 ...... Find a PRIME gateway that we can communicate with
FNDGWP ... ...... Find gateway address & get a packet ready for it
GGPIPK ... ...... Get & Initialize a GGP packet
PRNIH ... 42 ...... Print Internet host number string
GGPCKS ... 43 ...... Compute GGP level checksum (0 for now)
GGPACK ... 44 ...... Unimplemented
SETHGD ... 44 ...... Unimplemented
.GGPAK ... 44 ...... Unimplemented
.GGPSQ ... 44 ...... SOURCE-QUENCH message Unimplemented
.GGPAK ... 44 ...... ACKNOLEDGEMENT message Unimplemented
.GGPNK ... 44 ...... NEGATIVE-ACKNOLEDGEMENT message Unimplemented
.GGPNS ... 44 ...... Unimplemented
.GGPHD ... 44 ...... HOST-DISTANCE dummy (not %FULL)
.GGPRU ... 44 ...... ROUTING-UPDATE dummy (not %FULL)
!
IFNDEF %FULL,< PRINTX % %FULL not defined, assumed 0
%FULL==0 ; Turn on to be an active IP
>
; Accumulators used globally in this module:
DEFAC(GW,BFR) ; Points to a gateway block
DEFAC(GPKT,TPKT) ; Index register to point to GGP pkt
; Parameters:
IFNDEF MAXGWA,<MAXGWA==20> ; Number of GWs we will keep track of
IFNDEF MAXROU,<MAXROU==40> ; Number of routing names
; (Gateways and multi-homed hosts)
; Defined in STG as a variable
;GGPPT0==↑D<37*1000> ; Milliseconds of inter-ping interval
; (Prime number of seconds to minimize
; correlation with other things)
; (Not too often or there will be
; problems sending do down ARPANET hosts!)
DAY0==126317000000 ; Day-0 for GGP%FD pkts (1Jan80 0000-GMT)
; The file name to use:
IFKA < GWFILE: ASCIZ "<SYSTEM>INTERNET.GATEWAYS">
IFNKA < GWFILE: ASCIZ "SYSTEM:INTERNET.GATEWAYS">
; Structure of GGP packet (pointed to by GPKT)
DEFSTR(GPTYP,0,7,8) ; Type of message
GGP%RD==5 ; Redirect your output
GGP%DU==3 ; Destination unreachable
GGP%SQ==4 ; Source quench
GGP%RU==1 ; (old) Routine update
GGP%HD==101 ; (new) Host distance
.GGPSO==1 ; Where substructure begins
GGP%FD==102 ; (new) File date
GGP%AK==2 ; Acknowledgement
GGP%NK==↑D10 ; Negative acknowledgement
GGP%EC==↑D8 ; Echo
GGP%ER==0 ; Echo reply
GGP%NS==↑D9 ; Network Interface Status
DEFSTR(GPCOD,0,15,8) ; Code for GGP%DU
GGP%NU==0 ; Network unreachable
GGP%HU==1 ; Host unreachable
DEFSTR(GPSEQ,0,31,16) ; Sequence number in GGP%RU, GGP%AK,
; GGP%NK, and GGP%HD
DEFSTR(GPCKS,0,0,0) ; Checksum field (****Not Defined Yet)
; Other entries depend on GPTYP
; (Old) Routine update: GGP%RU
DEFSTR(GPNU,1,0,1) ; Source GW request update from Dest GW
DEFSTR(GPCNT,1,7,7) ; Count for GGP%RU
DEFSTR(GPDS1,1,15,8) ; Distance 1, followed by one octet per net
; Destination unreachable: GGP%DU
; Source quench: GGP%SQ
GIP%DU==<GIP%SQ==1> ; Beginning of included IP header
; Redirect your output: GGP%RD
DEFSTR(GPGWA,1,31,32) ; Gateway address for GGP%RD msgs
GIP%RD==2 ; Beginning of included IP header
; (New) Host distance: GGP%HD
; (New) File date: GGP%FD
DEFSTR(GPSRC,1,31,32) ; Source of Gateway data file in GGP%FD
DEFSTR(GPTAD,2,31,32) ; File time and date in GGP%FD
; Substructure of a Host Group Distance message:
DEFSTR(HGHST,0,31,32) ; 32-bit host (net, ...) identifier
DEFSTR(HGDST,1,31,16) ; Distance to that host group
HGSIZE==2 ; Words per subblock
; Note that GGP%RD, GGP%SQ, and GGP%RU have
; an Internet header and 64 bits in their bodies.
GGPNPW==PKTELI+.RTJST(-1,PIDO)+1 ; Minimum GGP packet size (1 data word)
; Tables kept and used by INGGP and INGWAY:
;GWTAB(GWX) is a list of pointers to gateway blocks that we know about.
;GWTAB ; Pointer to the table
;0,,GWTAB/ INTSEC,,Adr --> INTSEC,,Adr --> Gateway block
; ...
; INTSEC,,Adr --> Gateway block
; ...
; 0
; (MAXGWA)
; Structure of a Gateway block:
DEFSTR(GWUP,0,0,1) ; Gateway should be useable
DEFSTR(GWPIP,0,1,1) ; Ping in progress
DEFSTR(GWTYP,0,5,4) ; Gateway type
GW%PRM==1 ; Prime: Speaks GGP
GW%DUM==2 ; Dumb: Fwd's pkts, but that's all
GW%HST==3 ; Host: Avoid except in emergency
GW%AUP==4 ; Always-up: Fwds but doesn't reflect
DEFSTR(GWHIS,0,14,7) ; Ping history bits
DEFSTR(GWSPC,0,17,3) ; Successful ping count
.THRUP==<6*WID(GWHIS)>/8 ; Threshold to say it is up
.THRDN==<3*WID(GWHIS)>/8 ; Threshold to say it is down
IFL <<1←WID(GWSPC)>-1>-WID(GWHIS), PRINTX ?GWSPC too small
DEFSTR(GWICT,0,35,18) ; Interface count
.GWILS==1 ; Where in block to find the list
MXGWIC==6 ; Maximum number of interfaces
; Note: Really max number of nets can get to
; through a gateway plus 1
GWBKSZ==.GWILS+MXGWIC ; Size of a gateway block
;0,,NETGWA+I/ INTSEC,,Adr -->
; ...
; INTSEC,,Adr --> +0/ -1
; -1 ...
; ... +NET/ Address of GW to get to NET
; -1 ...
; ($NETS) (MAXNET)
;0,,LCLHID+0/ -1
; ...
; +NET/ Interface #,Our interface address on NET
; ...
; -1
; (MAXNET)
IFN %FULL,<
; ROUTE(hash(NET)) gives the current routine information for
; packets going to a given "network". Note that a network number
; is a 32-bit number which is the name of a host group. For
; instance 12,3,0,61 is BBNC; 12,0,0,0 is the ARPANET.
DEFSTR(RUDEL,0,0,1) ; Deleted slot in the hash table
DEFSTR(RUGWX,0,17,6) ; Gateway index
DEFSTR(RUGIN,0,35,18) ; Interface on that GW
DEFSTR(RUNET,1,35,36) ; The lookup key
RUBKSZ==2 ; Size of routing blocks
;ROUTAB ; Pointer to table
;LSTROU ; Pointer to stale routing table
> ; end IFN %FULL
;GGPINI Initialize G-G Protocol
;
; CALL GGPINI
;Ret+1: Always.
GGPINI::SE1CAL ; In case called from MDDT
LOCAL <I>
PUSH P,GW
MOVX T1,<377777777777> ; No run time
MOVEM T1,GGPTIM
MOVX T1,.GGPFM ; Set protocol number
MOVEM T1,GGPPCL
SETOM GGPMSG ; Use .PRIOU for messages
SETZM GGPPTM ; Clear time of next ping
SKIPE GGPIPQ ; Already have a queue head?
JRST GGPIN0 ; Yes.
MOVEI T1,QSZ ; Size of a queue head
CALL GETBLK ; Get one from free area
JUMPE T1,GGPIN9 ; No core
MOVEM T1,GGPIPQ ; Put where we can find it
CALL INITQ ; Initialize it
GGPIN0:
SKIPN GWTAB ; Is this a reinit?
JRST GGPIN2 ; No.
MOVSI I,-MAXGWA ; Set to scan GWTAB
GGPIN1: MOVE GW,GWTAB
ADDI GW,0(I) ; Point to actual entry
SETZ T1, ; Get a zero
EXCH T1,0(GW) ; Flush entry, get previous value
SKIPE T1 ; Was there one?
CALL RETBLK ; Yes. Give back storage
AOBJN I,GGPIN1 ; Do all GW blocks
JRST GGPIN4
GGPIN2: SETZM GGPSID ; Init the segment ID for GGP
MOVEI T1,MAXGWA ; Maximum number of gateways
CALL GETBLK ; Get a block of storage
JUMPE T1,GGPIN9 ; Crash
MOVEM T1,GWTAB
MOVEI T2,MAXGWA ; Size of the block
CALL CLRBLK ; Clear it out
IFN %FULL,<
MOVEI T1,MAXROU*RUBKSZ ; Size of a routine table
CALL GETBLK
JUMPE T1,GGPIN9
MOVEM T1,LSTROU ; Last thing we announced
MOVEI T1,MAXROU*RUBKSZ
CALL GETBLK
JUMPE T1,GGPIN9 ; No core
MOVEM T1,ROUTAB ; Here is the main routing table
> ; end IFN %FULL
HRLZ I,$NETS ; Set to scan NETGWA
GGPI4A: MOVEI T1,MAXNET ; Size of a gateway table
CALL GETBLK ; Get one
JUMPE T1,GGPIN9 ; No core
MOVEM T1,NETGWA(I) ; Set pointer in interface table
AOBJN I,GGPI4A
CALL SETROU ; Set up initial routes (none?)
GGPIN4:
IFN %FULL,<
MOVE T1,LSTROU ; Pointer to old table
MOVEI T2,MAXROU*RUBKSZ ; Size of it
CALL CLRBLK ; Clear it
MOVE T1,ROUTAB ; Pointer to main table
MOVEI T2,MAXROU*RUBKSZ
CALL CLRBLK
> ; end IFN %FULL
GGPIN5: CALL LODFIL ; Load the gateway file
CALL SETROU ; Set routes based on file
CALL PINGER ; Ping the gateways
MOVE T1,INETID+0 ; Our (primary) Internet name
MOVEM T1,GFSRC ; We are a source of gateway file
MOVEM T1,GFWHO ; And we are the one who said so
MOVE T2,GFCTAD ; Gateway file creation time and date
MOVEM T2,GFTAD ; TAD of file anywhere in catenet
CALL SNDGWD ; Send out this date
JRST GGPINX
GGPIN9: INBUG (HLT,<GGPINI: Crucial storage missing>,INGGP0)
GGPINX: SETOM GGPON
POP P,GW
RESTORE
RET
; LODFIL() Load the gateway file
;
; CALL LODFIL
;Ret+1: Always
LODFIL: LOCAL <JFH,CHNS>
SETO JFH, ; Indicate nothing to release
MOVEI T1,.FHSLF ; This fork
RCM ; Get channels which are on
MOVEM T1,CHNS ; Save for restoring
MOVEI T1,.FHSLF
MOVX T2,1B<.ICEOF> ; End of file channel
DIC ; Prevent unwanted interrupt
MOVX T1,GJ%OLD+GJ%SHT ; Want existing file
HRROI T2,GWFILE ; Pointer to filename string
GTJFN
JRST LODFIX ; Not there
MOVEM T1,JFH
MOVE T2,[FLD(7,OF%BSZ)+OF%RD] ; Want to read it
OPENF
JRST LODFIX
CALL PRCLIN ; Process lines in the file
MOVE T1,JFH
CLOSF
JFCL
LODFIX: SKIPL T1,JFH
RLJFN
JFCL
MOVEI T1,.FHSLF
MOVE T2,CHNS
AIC
RESTORE
RET
; PRCLIN(JFH) Process lines of the gateway file
;T1/ JFH of the file
;
; CALL PRCLIN
;Ret+1: Always. T1 still has the JFH
PRCLIN::LOCAL <JFH,BOL,ERRPNT,ERRCOL>
MOVEM T1,JFH ; Stash JFH in a save place
; Top of main per-line loop:
PRCLI1: MOVE T1,JFH ; Get the file JFH
RFPTR ; Find out where in file line is
JFCL
MOVEM T2,BOL ; Save beginning of line
CALL GETC ; First character of line
JUMPE T2,PRCLIX ; get out if end of file
CAIN T2,12 ; Linefeed?
JRST PRCLI1 ; Ignore blank lines
CAIN T2,";"
JRST PRCLI8 ; Flush comment line
CAIN T2,"C"
JRST PRCLI7 ; Go do CREATION command
BKJFN ; Back up so LOADGW can read 1st chr
JFCL ; Will ITRAP on BIN if error in T1
CALL LOADGW ; Load a gateway description
JUMPE T2,PRCLI1 ; Do next if no error
; Here when error detected in current line ***** Noone might be
; listening, Hang fork??
PRCLI2: MOVE T1,GGPMSG
SETZ T3,
SOUT ; Type the error string
HRROI T2,[ASCIZ " in file: "]
SOUT
MOVE T2,JFH
JFNS ; And the actual file name
HRROI T2,[ASCIZ "
"]
SOUT ; And a carriage return
MOVE T1,JFH
RFPTR ; Find out where we have read to
JFCL
SOS ERRPNT,T2 ; Save the error point
MOVE T2,BOL ; Beginning of the bad line
SFPTR
JFCL
SETOM ERRCOL ; Maybe nothing read of line
; Top of loop that types out a bad line
PRCLI3: MOVE T1,JFH
RFPTR ; Get the file pointer
JFCL
CAME T2,ERRPNT ; Up to the point of the error
JRST PRCLI4 ; No. Dont save column yet
MOVE T1,GGPMSG
RFPOS
HRRZM T2,ERRCOL ; Column where to show error
PRCLI4: MOVE T1,JFH
CALL GETC ; Get a character from bad line
SKIPN T2 ; End of file?
MOVEI T2,12 ; Yes. Use linefeed.
CAIN T2,12 ; End of line?
JRST PRCLI5 ; Yes. Done
MOVE T1,GGPMSG
BOUT ; Type a character
JRST PRCLI3 ; Do next one
PRCLI5: MOVE T1,GGPMSG
HRROI T2,[ASCIZ "
"]
SETZ T3,
SOUT ; Type and end of line terminal
JUMPLE ERRCOL,PRCLI6 ; Know where to show the error?
MOVEI T2," " ; Yes. Space over to it.
BOUT
SOJG ERRCOL,.-1 ; All the way.
PRCLI6: HRROI T2,[ASCIZ "↑
"]
SOUT
JRST PRCLI1 ; Try to finish the file
; Do CREATION command
PRCLI7: CALL GETC ; Skip over stuff following the C
MOVE T3,T2 ; Free up T2
HRROI T2,[ASCIZ "% INGGP: Premature EOF"]
JUMPE T3,PRCLI2 ; Go do the error if need be
CAIE T3," " ; One space is required separator
JRST PRCLI7 ; Loop til it is found
SETZ T2, ; Default flags
IDTIM ; Input the time and date
SKIPA T2,[-1,,[ASCIZ "% INGGP: Bad format in creation date"]]
MOVEM T2,GFCTAD ; Save our gateway file creation date
JUMPL T2,PRCLI2 ; Do error if need be
JRST PRCLI1 ; Do another command
; Here to flush a comment line
PRCLI8: CALL GETC ; Get a character
JUMPE T2,PRCLIX ; Get out if end of file
CAIE T2,12 ; End of line?
JRST PRCLI8 ; No.
JRST PRCLI1 ; Go read the next line.
PRCLIX: MOVE T1,JFH ; Preserve JFH as promised
RESTORE
RET
;NR GFCTAD,1 ; Gateway file creation time and date
; LOADGW(JFH) Load one gateway desciption and add to table
;T1/ JFH
;
; CALL LOADGW
;Ret+1: Always. T2 has 0 if no error or -1,,errorstring
; T1 preserved.
LOADGW: LOCAL <JFH,EOLFLG>
PUSH P,GW
MOVEM T1,JFH
MOVEI GW,0
MOVEI T1,GWBKSZ ; Size of a gateway block
CALL GETBLK ; Get a chunk of free storage
HRROI T2,[ASCIZ "% INGGP: Insufficient storage "]
SKIPN GW,T1
JRST LOADG9 ; Give error return
MOVEI T2,GWBKSZ ; Size of block
CALL CLRBLK ; Clear it out
SETZM EOLFLG ; End of line not seen
; Top of per-keyword loop:
LOADG1: MOVE T1,JFH
CALL GETC ; Get a character
JUMPE T2,LOADG8 ; Oops. End of file.
CAIN T2," " ; Space (control, etc)
JRST LOADG1 ; Yes. Flush it.
CAIL T2,"0"
CAILE T2,"9"
JRST LOADG4 ; Non-digit. Must be keyword
; Here to input an interface address in N H L I form.
LOADG2: SETZM T4 ; Clear the number accumulator
BKJFN ; Reread the digit
JFCL
LODG2A: MOVEI T3,↑D10 ; Decimal
NIN
JRST LOADG7 ; Null number?
LSH T4,↑D8 ; Make room for another byte
ADD T4,T2 ; Add it in
BKJFN ; Reread the terminator
JFCL
BIN
CAIN T2,15 ; Happens on TENEX
BIN ; Get the line feed, like TOPS20
JUMPE T2,LOADG8 ; Jump if end of file encountered
CAIN T2," " ; Space means another byte follows
JRST LODG2A ; Go get it
CAIN T2,12 ; End of line?
SETOM EOLFLG ; Yes. Remember to exit later.
CAIE T2,12 ; End of line
CAIN T2,"," ; End of address expression?
JRST LOADG3 ; Yes. Go enter into GW block
JRST LOADG7 ; Anything else is bad format.
; Put address in current GW block. Really all that is needed is
; those addresses that we can talk to directly, but having the
; other sides of the gateways allows the first level of routing to
; be set up.
LOADG3: LOAD T3,GWICT,(GW) ; Get current count
CAIL T3,MXGWIC ; Room for another?
JRST LOADG1 ; No.
ADDI T3,1 ; Bump the count
STOR T3,GWICT,(GW) ; Store back
ADDI T3,.GWILS-1 ; Offset to first empty slot
ADD T3,GW ; Where to store the address
MOVEM T4,0(T3) ; Insert interface address into GW block
SKIPN EOLFLG ; Read entire GW spec?
JRST LOADG1 ; No. Get another keyword/addr
JRST LOADG6 ; Yes. Go tie off this block
; Process a keyword
LOADG4: SETO T3, ; Keyword BAD flag
CAIN T2,"P" ; "PRIME"
MOVX T3,GW%PRM
CAIN T2,"D" ; "DUMB"
MOVX T3,GW%DUM
CAIN T2,"H" ; "HOST"
MOVX T3,GW%HST
CAIN T2,"A"
MOVX T3,GW%AUP ; "ALLWAYS-UP"
HRROI T2,[ASCIZ "% INGGP: Unknown keyword "]
JUMPL T3,LOADG9 ; Give error if invalid keyword
HRROI T2,[ASCIZ "% INGGP: Too many gateway type specs."]
JN GWTYP,(GW),LOADG9 ; Give error if already have spec
STOR T3,GWTYP,(GW) ; Set type into GW block
; Here to skip over the rest of the current keyword
LOADG5: CALL GETC ; Get a character
JUMPE T2,LOADG8 ; End of file?
CAIN T2,12 ; End of line?
JRST LOADG6 ; Yes. Go tie it off.
CAIE T2," " ; Space
CAIN T2,"," ; Or comma will end it
JRST LOADG1 ; Go read next keyword
JRST LOADG5 ; Keep reading the rest of this one
; Here to tie off the block which has been accumulating
LOADG6: LOAD T2,GWICT,(GW) ; Get count of interfaces on gateway
JUMPE T2,LOADG9 ; None(?) forget this line
XMOVEI T3,.GWILS(GW) ; Pointer to the interface list
LOAD60: MOVE T4,0(T3) ; Get an interface address
;***** got to go
LSH T4,-↑D24 ; Extract net number
CAIL T4,1 ; Reasonable # ?
CAIL T4,MAXNET
JRST LOAD64 ; No, skip that interface
SKIPL LCLHID(T4) ; Can we talk to this interface?
JRST LOAD61 ; Yes. Keep this GW block
LOAD64: ADDI T3,1 ; Try next interface address
SOJG T2,LOAD60 ; Done all?
JRST LOADG9 ; Yes. Flush unuseable GW
LOAD61: SETONE <GWUP,GWHIS>,(GW) ; Initialize in the UP state
MOVEI T1,WID(GWHIS) ; Number of bits of ping history
STOR T1,GWSPC,(GW) ; Set the successful ping count to match
MOVE T3,GWTAB ; Pointer to the table
MOVEI T4,MAXGWA ; Size of it
LOAD62: SKIPN 0(T3) ; Empty slot?
JRST LOAD69 ; Yes.
ADDI T3,1
SOJG T4,LOAD62
HRROI T2,[ASCIZ "% INGGP: Too many gateways "]
JRST LOADG9
LOAD69: MOVEM GW,0(T3) ; Insert in table
SETZ T2, ; Give successful return
JRST LOADGX
LOADG7: SKIPA T2,[-1,,[ASCIZ "% INGGP: Bad format "]]
LOADG8: HRROI T2,[ASCIZ "% INGGP: Premature end of file "]
LOADG9: PUSH P,T2
SKIPE T1,GW
CALL RETBLK
POP P,T2
LOADGX: MOVE T1,JFH
POP P,GW
RESTORE
RET
; GETC(JFH) Get a character from a file
;T1/ JFH of the file
;
; CALL GETC
;Ret+1: T1 preserved. T2 has the chr or 0 if end of file
GETC: BIN ; Read the file
JUMPN T2,GETC2 ; Jump if a character gotten
GTSTS ; Read a null.
TXNN T2,GS%EOF ; At end of file?
JRST GETC ; No. Just flush the null
MOVEI T2,0 ; Set to return the EOF code
JRST GETCX
GETC2: CAIE T2,14 ; Formfeed?
CAIN T2,37 ; TENEX EOL?
MOVEI T2,12 ; Convert to linefeed
CAIN T2,12 ; Linefeed?
JRST GETCX ; Return that
CAIGE T2," " ; Other control?
JRST GETC ; Yes. Flush
CAIL T2,"a"
CAILE T2,"z"
CAIA ; Not lowercase
SUBI T2,"a"-"A" ; Raise lowercase
GETCX: RET
;SNDGWD Send our gateway file date to all
;(no args)
;
; CALL SNDGWD
;Ret+1: Always.
SNDGWD: LOCAL <GWX>
PUSH P,GW
MOVSI GWX,-MAXGWA ; Set to scan GWTAB
SNDGW1: HRRZ GW,GWX ; Get offset into table
ADD GW,GWTAB ; Add in base of table
SKIPN GW,0(GW) ; Get pointer to gateway block
JRST SNDGWX ; Nothing in this slot
LOAD T1,GWTYP,(GW) ; Get the gateway type code
CAIE T1,GW%PRM ; Prime?
CAIN T1,GW%HST ; Host?
CALL SNDGFT ; Those guys might be interested
AOBJN GWX,SNDGW1 ; Loop over all gateways.
SNDGWX: POP P,GW
RESTORE
RET
;SNDGFT(GW) Send gateway file date and source to a gateway
;GW/ Pointer to gateway block
;
; CALL SNDGFT
;Ret+1: Always
SNDGFT: PUSH P,PKT ; Protect globals
PUSH P,GPKT
MOVEI T1,↑D12 ; Need 12 bytes of data space
CALL FNDGWP ; Get gateway address & setup GGP packet
JUMPE PKT,SNDGFX ; No address of no room
; T1/ GW adr, T2/ our adr on that net
; Set up GGP part of packet
MOVEI T1,GGP%FD ; File date code
STOR T1,GPTYP,(GPKT) ; Store as GGP type
MOVE T1,GFSRC ; Host which has the file
STOR T1,GPSRC,(GPKT) ; Say we it can be had
MOVE T2,GFTAD ; GTAD of creation
IFKA< MOVEI T3,0(T2) ; Second within day
DIVI T3,↑D<24*60*60> ; Compute fraction of a day
LSH T3,-↑D17 ; To right half
HRR T2,T3 ; Form TOPS20 type GTAD
>
SUB T2,[DAY0] ; Make it fit in 32-bits easily
LSH T2,-4
STOR T2,GPTAD,(GPKT)
CALL GGPCKS ; Compute it
STOR T1,GPCKS,(GPKT) ; Insert in packet
CALL SNDGAT ; Send it off
SNDGFX: POP P,GPKT
POP P,PKT
RET
;SETROU Set routing tables from GW status tables
; Can be called just about anytime. Usually,
; tables are maintained incrementally, however.
; CALL SETROU
;Ret+1: Always.
SETROU: LOCAL <IPTR>
HRLZ IPTR,$NETS ; Set to scan interface table
SETRO1: SKIPG T2,NETGWA(IPTR) ; Pick up a table pointer
JRST SETRO8
MOVEI T1,MAXNET-1 ; Count for BLT
XMOVEI T3,1(T2) ; Dest for blt
SETOM 0(T2)
CALL XBLTA ; Do the appropriate BLT.
SETRO8: AOBJN IPTR,SETRO1 ; Do all interfaces
CALL RSTDSP ; Reset gateway dispatches
RESTORE
RET
;RSTDSP Reset gateway dispatches which are not set now
;
; CALL RSTDSP
;Ret+1: Always. As many -1 (empty) marks removed as possible
RSTDSP: LOCAL <GWX,IPTR,ICTR,GTAB>
PUSH P,GW
MOVSI GWX,-MAXGWA ; Set to scan GWTAB
RSTDS1: HRRZ GW,GWX ; Get current offset in to table
ADD GW,GWTAB ; Add in base of table
MOVE GW,0(GW) ; Get pointer to gateway block
JUMPE GW,RSTDS9 ; Empty slot in table
JE GWUP,(GW),RSTDS9 ; Avoid using gateways which are down
XMOVEI IPTR,.GWILS(GW) ; Pointer to interface list
LOAD ICTR,GWICT,(GW) ; Get interface count
RSTDS2: MOVE GTAB,0(IPTR) ; Get interface address
LSH GTAB,-↑D24 ; Net number of that interface
SKIPG LCLHID(GTAB) ; One we are connected to?
JRST RSTDS8 ; No. Move on to next interface addr
LOAD T1,INTNUM,LCLHID(GTAB) ; Get interface number
MOVE GTAB,NETGWA(T1) ; Get pointer to dispatch table, that int.
XMOVEI T3,.GWILS(GW) ; Set up to scan interface list again
LOAD T4,GWICT,(GW) ; Putting exit points in this GWTAB
RSTDS3: MOVE T2,0(T3) ; Get an interface address
LSH T2,-↑D24 9 Get net number
ADD T2,GTAB ; Corresponding entry in current table
MOVE T1,0(IPTR) ; The address we are talking about
SKIPGE 0(T2) ; Slot currently empty?
MOVEM T1,0(T2) ; Yes. Stuff it.
ADDI T3,1 ; Move on to next interface address
SOJG T4,RSTDS3 ; Loop til all done.
RSTDS8: ADDI IPTR,1 ; Move to next interface
SOJG ICTR,RSTDS2 ; Loop til all done.
RSTDS9: AOBJN GWX,RSTDS1 ; Loop over all GWs
MOVE T1,TODCLK ; Update time of
ADD T1,GGPRT0 ; next asynchronous
MOVEM T1,GGPRTM ; call
POP P,GW
RESTORE
RET
; Top level GGP Processing routine. Called from main Internet
; fork loop.
; (no args)
;
; CALL GGPPRC
;Ret+1: Always
GGPPRC::SETZM GGPFLG ; Clear run request flag
SKIPN GGPON
JRST GGPPRX
CALL GGPDSP ; Dispatch any msgs which are waiting
MOVE T1,GGPPTM ; Time of next PINGER
CAMGE T1,TODCLK ; Over due?
CALL PINGER ; Yes. Do ping stuff.
; Note: PINGER may call RSTDSP which updates GGPRTM so it doesn't get recalled
MOVE T1,GGPRTM ; Time of next RSTDSP
CAMGE T1,TODCLK ; Over due?
CALL RSTDSP ; Yes. Reset dispatches
GGPPRX: RET
; Check Routine for GGP. Tells when to run next
;T1/ A TODLCK
;
; CALL GGPCHK
;Ret+1: Always. T1 has min of input T1 and when we should run next.
GGPCHK::MOVX T2,<377777777777> ; No run needed
SKIPN GGPON
JRST GGPCH9
CAMLE T2,GGPPTM ; Check against PINGER time
MOVE T2,GGPPTM ; That is sooner
CAMLE T2,GGPRTM ; Check against RSTDSP time
MOVE T2,GGPRTM ; That is sooner
GGPCH9: MOVEM T2,GGPTIM ; Time of next GGP run
CAMLE T1,T2
MOVE T1,T2
RET
; PINGER() Ping gateways to see if they are alive
;
; CALL PINGEN
;Ret+1: Always. GGPPTM reset for next run
PINGER: LOCAL <I,REDOF>
PUSH P,GW
SETZ REDOF, ; Clear redo-routes flag
MOVSI I,-MAXGWA ; Set to scan the gateway table
PINGE1: HRRZ GW,I ; Get offset into table
ADD GW,GWTAB ; Add base pointer
SKIPN INTSCR ; No pings if secure
SKIPN GW,0(GW) ; Get pointer to gateway
JRST PINGE8 ; Unoccupied slot
LOAD T1,GWHIS,(GW) ; Get the history bits
LOAD T2,GWSPC,(GW) ; Get the successful ping count
TRNE T1,1 ; Test bit about to be forgotten
SUBI T2,1 ; Forgotting a success
SKIPGE T2 ; Avoid negative while down
MOVEI T2,0 ; This is as bad as you can get
LOAD T3,GWPIP,(GW) ; See if previous ping still in progress
XORI T3,1 ; Flip sense to indicate success
LSH T3,WID(GWHIS)-1 ; Move to left end
LSH T1,-1 ; Flush the oldest history bit
IOR T1,T3 ; Include in history bits
SKIPE T3 ; Did we add a success to the list
ADDI T2,1 ; Yes. Count it up
CAILE T2,WID(GWHIS) ; Check for overflow
MOVEI T2,WID(GWHIS) ; Limit to max
STOR T2,GWSPC,(GW) ; Store back the count
STOR T1,GWHIS,(GW) ; Store back the bits
LOAD T4,GWUP,(GW) ; Get current state
MOVE T3,T4 ; Save a copy
CAIL T2,.THRUP ; Enough success to say it's up?
MOVEI T4,1 ; Yes
CAIG T2,.THRDN ; So few that it is down?
MOVEI T4,0 ; Yes.
STOR T4,GWUP,(GW) ; Set new value
XOR T3,T4 ; Compare to see if change
ADDM T3,REDOF ; If so, count up changes
JUMPE T3,PINGE7 ; Jump if no change
JUMPN T4,PINGE7 ; Jump if it came up
CALL GWDOWN ; Yes. Flush from tables now.
PINGE7: SETONE GWPIP,(GW) ; Set ping-in-progress bit
CALL SNDPNG ; Send a ping to guy in GW
PINGE8: AOBJN I,PINGE1 ; Loop over all gateways
SKIPLE REDOF ; Any GW change state?
CALL RSTDSP ; Yes. Reset dispatches
MOVE T1,GGPPT0 ; Interping interval
ADD T1,TODCLK ; Time of next ping/check
MOVEM T1,GGPPTM ; Save for scheduling
POP P,GW
RESTORE
RET
;SNDPNG Send a ping message to a GW
; This is an ECHO message if we are sending to a PRIME gateway, or
; an ECHO REPLY addressed to ourself if testing a non-PRIME
; gateway. Net result is that we get back only ECHO REPLIES.
;GW/ Pointer to gateway block
;
; CALL SNDPNG
;Ret+1: Always.
SNDPNG: PUSH P,PKT
PUSH P,GPKT
LOAD T1,GWTYP,(GW) ; Gateway type code
CAIE T1,GW%AUP ; Always up?
JRST SNDPN1 ; No. Must actually send a ping
SETZRO GWPIP,(GW) ; Fake a successful ping
JRST SNDPNX
SNDPN1: MOVEI T1,1 ; GGP packet size
CALL FNDGWP ; Get gateway address & setup GGP packet
JUMPE PKT,SNDPNX ; No address of no room
; T1/ GW adr, T2/ our adr on that net
MOVEI T3,GGP%EC ; Echo type
LOAD T4,GWTYP,(GW) ; Get type
CAIN T4,GW%PRM ; Prime?
JRST SNDPN6 ; Yes, SRC & DST already set
EXCH T1,T2 ; Swap source and destination
MOVEI T3,GGP%ER ; ECHO-REPLY code
SETONE PNLCL,(PKT) ; No local delivery, send to "source"
STOR T2,PISH,(PKT) ; Make it look like it came from there
STOR T1,PIDH,(PKT) ; Make it go there
SNDPN6: STOR T3,GPTYP,(GPKT) ; Set into GGP section
CALL GGPCKS ; Compute checksum
STOR T1,GPCKS,(GPKT) ; Insert in packet
CALL SNDGAT ; Send it off
SNDPNX: POP P,GPKT
POP P,PKT
RET
;GWDOWN Gateway just detected down
; Called by the PINGER when too few pings returned
;GW/ Pointer to gateway block
;
; CALL GWDOWN
;Ret+1: Always. GWUP bit cleared and all interfaces removed from tables
GWDOWN: LOCAL <IFX,NTX,GWX,GWSAV>
MOVEM GW,GWSAV ; Save GW
HRLZ IFX,$NETS ; Set to scan interface table
GWDOW1: MOVSI NTX,-MAXNET ; Set to scan a table of interfaces
SKIPG NETGWA(IFX)
JRST GWDOW9
GWDOW2: HRRZ GWX,NTX ; Offset into current table
ADD GWX,NETGWA(IFX) ; Which gateway address to consider
SKIPGE T1,0(GWX) ; Get the address
JRST GWDOW8 ; None there
CALL FINDGW ; Find owning gateway
JUMPE GW,GWDOW8 ; Not there?
CAMN GW,GWSAV ; Is on the gw which went down?
SETOM 0(GWX) ; Flush
GWDOW8: AOBJN NTX,GWDOW2 ; Scan entire dispatch table
GWDOW9: AOBJN IFX,GWDOW1 ; And all interfaces
MOVE GW,GWSAV ; Restore the gateway pointer
RESTORE
RET
; GGPDSP Dispatch on GGP message type
;
; CALL GGPDSP
;Ret+1: Always.
GGPDSP: PUSH P,PKT
PUSH P,GPKT
GGPDS1: MOVE T1,GGPIPQ ; Pointer to input queue head
LOAD PKT,QNEXT,(T1) ; Get first thing on queue
SETSEC PKT,INTSEC ; Make extended address
CAMN PKT,T1 ; Pointer to head means empty
JRST GGPDSX ; Empty
MOVE T1,PKT ; What to dequeue
CALL DQ ; Get it off queue (NOSKED not needed)
LOAD GPKT,PIDO,(PKT) ; Internet data offset
; ADD GPKT,PKT ; Get pointer to GGP portion
ADDI GPKT,PKTELI(PKT) ; Skip over local information
CALL GGPCKS ; Check GGP Checksum
JUMPE T1,GGPDS2 ; Jump if ok
MOVX T1,PT%GKC ; Trace packets w/ bad checksum
TDNE T1,INTTRC ; Want trace?
CALL PRNPKI ; Yes
MOVX T1,IPP%PT ; Checksum parameter problem
MOVX T2,12 ; 12-13th octet are checksum
CALL INCEM ; Report error
AOS BADPCT ; Count bad packets
JRST GGPDS9 ; Flush it
GGPDS2: MOVX T1,PT%GDI ; Trace packets received
TDNE T1,INTTRC ; Want trace?
CALL PRNPKI ; Yes
LOAD T1,GPTYP,(GPKT) ; What kind of message it is
HRLZ T2,NGGPMT
CAME T1,GGPTTB(T2) ; Matches this one?
AOBJN T2,.-1 ; No. Try next.
JUMPGE T2,[ MOVX T1,PT%GKT ; Jump if not found
TDNE T1,INTTRC ; Want trace?
CALL PRNPKI ; Yes, Trace packets w/ unknown type
MOVX T1,IPP%PT ; GPTYP parameter problem
MOVE T2,GPKT
SUBI T2,PKTELI(PKT)
IMULI T2,4
; ADDI T2,0 ; 0th octet in GGP part
CALL INCEM ; Report error
JRST GGPDS9]
LOAD T3,PIPL,(PKT) ; Packet length in bytes
LOAD T4,PIDO,(PKT) ; Internet data offset in words
ASH T4,2 ; Make that bytes
SUB T3,T4 ; Number of bytes in GGP part
SUB T3,GGPMDC(T2) ; Minus min number req'd for this type
JUMPL T3,[ MOVX T1,PT%GKS ; Jump if packet too short
TDNE T1,INTTRC ; Want trace?
CALL PRNPKI ; Yes
MOVX T1,IPP%PT ; PIPL parameter problem
MOVX T2,2 ; 2nd octet is PIPL
CALL INCEM ; Report error
JRST GGPDS9]
CALL @GGPRTB(T2) ; Call action routine
GGPDS9: CALL RETPKT ; Return the packet to free storage
JRST GGPDS1 ; unless routine skips
GGPDSX: POP P,GPKT
POP P,PKT
RET
; GGP Type code tables
.Z==20
GGPTTB: BLOCK .Z ; Table of type codes (ordered by frequency)
GGPRTB: BLOCK .Z ; Action routines
; NB: they might skip return to retain PKT
GGPMDC: BLOCK .Z ; Table of minimum data counts
DEFINE GGPCM (C<XX>,L<10000>)<
IFGE .Y-.Z,<IF1 <PRINTX % Too many GGP type codes for table>>
IFL .Y-.Z,<
.X==.
RELOC GGPTTB+.Y
GGP%'C
RELOC GGPRTB+.Y
MSEC1,,.GGP'C
RELOC GGPMDC+.Y
L
RELOC .X
.Y=.Y+1
>
>
.Y==0
GGPCM RU,8
GGPCM AK,4
GGPCM RD,8+MINIHS+8
GGPCM SQ,4+MINIHS+8
GGPCM DU,4+MINIHS+8
GGPCM NK,4
GGPCM ER,1
GGPCM EC,1
GGPCM HD,14
GGPCM FD,14
GGPCM NS,1
NGGPMT: -<.Y>
IFG .Z-.Y,<REPEAT .Z-.Y,< GGPCM>>
; Dummy message
GGP%XX==-1
.GGPXX: RET
; Process an ECHO message:
.GGPEC: LOAD T1,PIDH,(PKT) ; Destination (us)
LOAD T2,PISH,(PKT) ; Source (who wants echo)
STOR T1,PISH,(PKT) ; We are the echoer
STOR T2,PIDH,(PKT) ; Sender is the echoee
MOVEI T3,GGP%ER ; Echo reply code
STOR T3,GPTYP,(GPKT) ; Set as the GGP type code
; Following doesn't work since RETPKT ignores PPROG, RETSKP instead
; SETONE PPROG,(PKT) ; Save so it can be returned by caller
CALL SNDGAT ; Send it back
AOS (P) ; Skip return to save packet
RET
; Process an ECHO-REPLY message:
.GGPER: PUSH P,GW
LOAD T1,PISH,(PKT) ; Who it appears to be from (maybe us)
XMOVEI T2,..GPER ; Routine to call
CALL FNDAGW ; Look up the gateway blocks
GGPERX: POP P,GW
RET
..GPER: JUMPE GW,.GPERX ; Not there
SETZRO GWPIP,(GW) ; Clear ping-in-progress bit
.GPERX: RET
; Process a REDIRECT message
; Note: The current version of the GGP does not support hosts with
; multiple interfaces. For example, a GGP%RD message assumes that we can
; look at the destination Host field of the packet which triggered the
; REDIRECT (header is in the REDIRECT msg), and tell which gateway we
; should stop sending to. But we cannot tell if there are more than one
; interface. The following code assumes that the tables have not changed
; (say by a background process doing load splitting) since the packet
; was sent. Thus we can look at the destination net and find the right
; gateway table.
.GGPRD: LOAD T1,PIDH,+GIP%RD-PKTELI(GPKT) ; Dest. which trigger lossage
; [Maybe we should look at the local ldr]
LSH T1,-↑D24 ; Get net number
CAIL T1,1
CAILE T1,MAXNET ; Check number for valid
JRST GGPRDX ; What is that GW talking about????
SKIPGE T4,LCLHID(T1) ; Are we connected to that net?
JRST GGPRDX ; No???
LOAD T4,INTNUM,T4 ; Interface number
MOVE T4,NETGWA(T4) ; Pointer to gateway table
ADD T1,T4 ; Address of GW to dest net via this int.
LOAD T2,GPGWA,(GPKT) ; Here is the replacement
MOVEM T2,0(T1) ; Stuff in the table
GGPRDX: RET
; Process an UNREACHABLE message
; This means that all paths into the indicated network are broken.
; This is because all the gateways talk to each other and agree about down
; nets. So, all gateway dispatches can be wiped out. Actually, we will
; leave dispatches through dumb gateways since they might still work.
; Every once in a while, a background process will call RSTDSP to re-init
; the tables. This allows us to use nets which have come up again.
.GGPDU: LOCAL <IPTR,NPTR>
PUSH P,GW
LOAD T1,GPCOD,(GPKT) ; Get code
CAIE T1,GGP%NU ; Is it a net that is unreachable?
JRST GGPDUX ; Nope. Can't handle others yet
HRLZ IPTR,$NETS ; Set to scan all interfaces
GGPDU1: SKIPG T3,NETGWA(IPTR) ; Get pointer to gateway table
JRST GGPDU9
; ***** will have to go -↑D24
LOAD T1,PIDHN,+GIP%DU-PKTELI(GPKT) ; Get destination net
ADD T3,T1 ; Point to slot for this net
MOVE T1,0(T3) ; Get gateway address
XMOVEI T2,..GPDU ; Routine to call
CALL FNDAGW ; Set up GW to point at its block
; and call ..GPDU
GGPDU9: AOBJN IPTR,GGPDU1 ; Loop over all interfaces
GGPDUX: POP P,GW
RESTORE
RET
..GPDU: JUMPE GW,..GPDX ; Not there.
LOAD T4,GWTYP,(GW) ; Get the type code
CAIE T4,GW%DUM ; Non-speaking GW?
SETOM 0(T3) ; No. Wipe it out.
..GPDX: RET
IFN %FULL,<
; Process a ROUTING-UPDATE message:
.GGPRU: LOCAL <CNT,NETN,PTR>
MOVEI NETN,1 ; First net in packet is 1
LOAD CNT,GPCNT,(GPKT) ; Get count from packet
MOVE T1,.-1 ; Get pointer to byte pointer
MOVE PTR,0(T1) ; Get pointer to net list
GGPRU1: JUMPLE CNT,GGPRU3 ; Jump if all have been done
GGPRU2: MOVE T1,NETN ; Current net number
LSH T1,↑D24 ; Make into a 32-bit style net number
ILDB T2,PTR ; Get distance from this net
CALL SETHGD ; Set the host group distance
ADDI NETN,1 ; Ready for next net
SOJG CNT,GGPRU2 ; Move on to next
GGPRU3: CALL GGPACK ; Send an ACK
RESTORE
RET
> ; end IFN %FULL
IFN %FULL,<
; Process a HOST-DISTANCE message:
.GGPHD: LOCAL <CNT,HDBLK>
LOAD CNT,PIPL,(PKT) ; Get Internet packet length in bytes
LOAD T2,PIDO,(PKT) ; Internet data offset in words
ADDI T2,.GGPSO ; Add offset to first subblock
ASH T2,2 ; Make that bytes
SUB CNT,T2 ; Number of bytes of subblocks
IDIVI CNT,4*HGSIZE ; Size of a subblock
JUMPN CNT+1,GGPHDX ; Forget it if it has bad format
XMOVEI HDBLK,.GGPSO(GPKT) ; Pointer to subblock
GGPHD1: LOAD T1,HGHST,(HDBLK) ; Get 32-bit host group
LOAD T2,HGDST,(HDBLK) ; Get distance thereto
CALL SETHGD ; Set distance in our tables
ADDI HDBLK,HGSIZE ; Move to next subblock
SOJG CNT,GGPHD1 ; Do it
CALL GGPACK ; Generate an acknowledgement
GGPHDX: RESTORE
RET
> ; end IFN %FULL
; Process a FILE DATE message:
.GGPFD: PUSH P,GW
LOAD T1,GPSRC,(GPKT) ; Where the file is available
LOAD T2,GPTAD,(GPKT) ; What its creation date is
LOAD T3,PISH,(PKT) ; Who says so
LSH T2,4 ; Make in to our natural GTAD format
ADD T2,[DAY0]
IFKA < HRLZ T4,T2 ; Get fraction of day
LSH T4,-1 ; Make arithmetic fraction
MULI T4,↑D<24*60*60> ; Get second within day
HRR T2,T4 ; Form TENEX GTAD
>
CAMN T2,GFTAD ; Compare with what we already know
JRST GGPFDX ; Equal means we are up-to-date here
CAMG T2,GFTAD ; Packet announces something newer?
JRST GGPFD4 ; No. Tell him what we know
MOVEM T2,GFTAD ; Yes. Grab that info and tell operator
MOVEM T1,GFSRC ; Save source
MOVEM T3,GFWHO ; and who told us about the new info
CALL ..GPFD ; Output message
JRST GGPFDX
GGPFD4: MOVE T1,GFWHO ; Who is giving us the old info
CALL FINDGW ; Set up GW
SKIPE GW ; Found it?
CALL SNDGFT ; Send him our more recent info
GGPFDX: POP P,GW
RET
..GPFD: MOVE T1,GGPMSG
HRROI T2,[ASCIZ "
% Internet address "]
SETZ T3,
SOUT
MOVE T1,GGPMSG
MOVE T2,GFWHO
CALL PRNIH ; Print Internet Host Number or Name
HRROI T2,[ASCIZ " says there is a new "]
SETZ T3,
SOUT
HRROI T2,GWFILE
SOUT
HRROI T2,[ASCIZ " available from "]
SOUT
MOVE T2,GFSRC
CALL PRNIH
HRROI T2,[ASCIZ "
Please get a copy, check its contents and install it.
"]
SETZ T3,
SOUT
RET
; FINDGW Set GW to point to (first) gateway block containing c(T1)
;T1/ An Internet Gateway address
;
; CALL FINDGW
;Ret+1: Always. GW has pointer to block or 0 if not found
FINDGW: LOCAL <GWX,ICT,ILS>
MOVSI GWX,-MAXGWA ; Size of table
FINDG1: HRRZ GW,GWX ; Get table offset
ADD GW,GWTAB ; Add base
SKIPN GW,0(GW) ; Get pointer to gateway block
JRST FINDG9 ; Empty slot
XMOVEI ILS,.GWILS(GW) ; Pointer to interface list
LOAD ICT,GWICT,(GW) ; Number of interfaces
FINDG2: CAMN T1,(ILS) ; Match?
JRST FINDGX ; Yes. Get out.
ADDI ILS,1 ; Ready for next time
SOJG ICT,FINDG2 ; Try next interface
FINDG9: AOBJN GWX,FINDG1 ; Try next gateway
MOVEI GW,0 ; Indicate failure
FINDGX: RESTORE
RET
; FNDAGW Set GW to point to each gateway block with address in T1
; and call routine specified by T2
;T1/ An interface address
;T2/ Routine to call with GW set (must preserve all T* registers)
; Cannot use caller's LOCALs
;
; CALL FNDAGW
;Ret+1: Always.
FNDAGW: LOCAL <GWX,ICT,ILS>
MOVSI GWX,-MAXGWA ; Size of table
FNDAG1: HRRZ GW,GWX ; Get table offset
ADD GW,GWTAB ; Add base
SKIPN GW,0(GW) ; Get pointer to gateway block
JRST FNDAG9 ; Empty slot
XMOVEI ILS,.GWILS(GW) ; Pointer to interface list
LOAD ICT,GWICT,(GW) ; Number of interfaces
FNDAG2: CAMN T1,(ILS) ; Match?
CALL (T2) ; Yes. Call routine.
ADDI ILS,1 ; Ready for next time
SOJG ICT,FNDAG2 ; Try next interface
FNDAG9: AOBJN GWX,FNDAG1 ; Try next gateway
FNDAGX: RESTORE
RET
; FNDPGW Find a PRIME gateway
;T1/ Hint - desired network number
;
; CALL FNDPGW
;Ret+1: Always. T1 has LOCAL address (or 0 if none) & T3 has interface #
FNDPGW::LOCAL <GWX,ICT,ILS>
PUSH P,GW ; Save register
MOVSI GWX,-MAXGWA ; Size of table
FNDPG1: HRRZ GW,GWX ; Get table offset
ADD GW,GWTAB ; Add base
SKIPN GW,0(GW) ; Get pointer to gateway block
JRST FNDPG9 ; Empty slot
LOAD T3,GWTYP,(GW) ; Looking for PRIME
CAIE T3,GW%PRM
JRST FNDPG9 ; This isn't one
JE GWUP,(GW),FNDPG9 ; Must be up
XMOVEI ILS,.GWILS(GW) ; Pointer to interface list
LOAD ICT,GWICT,(GW) ; Number of interfaces
FNDPG2: MOVE T3,(ILS) ; Get one of its addresses
; *****
LSH T3,-↑D24 ; Find net #
CAIL T3,1
CAIL T3,MAXNET
JRST FNDPG4 ; ??
MOVE T3,LCLHID(T3) ; Get address & interface #
JUMPLE T3,FNDPG4 ; Not a LOCAL net
MOVE T1,T3 ; Extract local net address
TLZ T1,740000 ; Just 32 bits
LOAD T3,INTNUM,(T3) ; Interface # too
JRST FNDPGX ; All set
FNDPG4: ADDI ILS,1 ; Ready for next time
SOJG ICT,FNDPG2 ; Try next interface
FNDPG9: AOBJN GWX,FNDPG1 ; Try next gateway
MOVEI T1,0 ; Indicate failure
FNDPGX: POP P,GW ; Restore reg
RESTORE
RET
; FNDGWP Find address of a gateway
; T1/ # octets in GGP packet to be sent
; GW/ (Extended) address of a gateway block
;
; CALL FNDGWP
; JUMPE PKT,error
;Ret+1: Always, PKT=0 if error
; if no error
; PKT & GPKT set
; T1/ Addresss of gateway
; T2/ Our (primary) address
FNDGWP: LOCAL <GGPSZB,GWADR,OURADR>
MOVEM T1,GGPSZB
XMOVEI T3,.GWILS(GW) ; Pointer to interface list
LOAD T4,GWICT,(GW) ; Count of interfaces
FNDGWR: MOVE GWADR,0(T3) ; Get an interface address from this GW
MOVE T2,GWADR ; Copy it
LSH T2,-↑D24 ; Extract network number
ADDI T3,1 ; Advance to next address in list
CAIL T2,1 ; Reasonable net # ?
CAIL T2,MAXNET
JRST FNDGWT ; No
SKIPL OURADR,LCLHID(T2) ; Can we talk to this interface?
JRST FNDGWV ; Yes. Go do it.
FNDGWT: SOJG T4,FNDGWR ; Loop over all
SETZ PKT, ; Error return
JRST FNDGWX ; Not crucial if we cannot find it
FNDGWV: MOVE T1,GGPSZB
CALL GGPIPK ; Initialize packet
JUMPE PKT,FNDGWX ; No space
MOVE T2,OURADR ; Our Internet name on that net
TLZ T2,740000 ; Clean it up
STOR T2,PISH,(PKT) ; That's who it is from
MOVE T1,GWADR ; Gateway Address
STOR T1,PIDH,(PKT) ; This is the destination
FNDGWX: RESTORE
RET
; GGPIPK Get & Initialize a GGP packet
;T1/ # octets of GGP packet
;
; CALL GGPIPK
;Ret+1: Always. PKT=0 if no memory error; PKT & GPKT set if ok
GGPIPK: LOCAL <GGPSZB,GGPSZW>
MOVEI GGPSZB,MINIHS(T1) ; Save (min IP)+GGP size, octets
ADDI T1,3
ASH T1,-2 ; GGP words
ADDI T1,PKTELI+.RTJST(-1,PIDO) ; Plus local & net & IP
MOVEM T1,GGPSZW ; Save packet size, words
CALL GETBLK ; Get storage in which to build pkt
SKIPN PKT,T1 ; Put in standard place
JRST GGPIPX ; Lose, PKT is 0
MOVE T2,GGPSZW ; Size again
CALL CLRBLK ; Clear all flags, checksum, etc
MOVEI T1,.INTVR ; Internet Protocol version
STOR T1,PIVER,(PKT)
MOVEI GPKT,<MINIHS+3>/4 ; Min. Internet header size
STOR GPKT,PIDO,(PKT) ; Set as Internet Data offset
ADDI GPKT,PKTELI ; Skip over local
ADD GPKT,PKT ; & IP sections
STOR GGPSZB,PIPL,(PKT)
AOS T1,GGPSID ; Get next segment ID
STOR T1,PISID,(PKT) ; Put in packet
MOVEI T1,2 ; GGP Time to live
STOR T1,PITTL,(PKT) ; A local net requires 1 + 1 extra
MOVEI T1,.GGPFM ; Protocol is Gateway-to-Gateway
STOR T1,PIPRO,(PKT)
GGPIPX: RESTORE ; Failure return
RET
;PRNIH(32-bit number) Print Internet Host Number/String
;T1/ JFH
;T2/ The 32-bit number
;
; CALL PRNIH
;Ret+1: Always.
PRNIH: MOVE T4,T2 ; Save a copy
MOVEI T3,↑D10 ; Decimal seems to be standard these days
LDB T2,[POINT 8,T4,11] ; Net byte
NOUT
JFCL
MOVEI T2," "
BOUT
LDB T2,[POINT 8,T4,19] ; Host byte
NOUT
JFCL
MOVEI T2," "
BOUT
LDB T2,[POINT 8,T4,27] ; Logical host byte
NOUT
JFCL
MOVEI T2," "
BOUT
LDB T2,[POINT 8,T4,35] ; IMP byte
NOUT
JFCL
RET
; GGPCKS Compute GGP level checksum
;PKT/ Pointer to Internet portion of packet
;GPKT/ Pointer to GGP section thereof
;
; CALL GGPCKS
;Ret+1: Always. T1 has checksum.
GGPCKS: MOVEI T1,0 ; Not defined yet
RET
; Things not yet done:
IFE %FULL,<
.GGPHD:
.GGPRU:
> ; end IFE %FULL
.GGPAK:
.GGPSQ:
.GGPNK:
.GGPNS:
GGPACK:
SETHGD:
RET
TNXEND
END